package com.ibm.risk.irmp.common.auth.sso;

import com.ibm.risk.irmp.common.exception.AuthenticationException;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.GenericFilterBean;

import java.io.IOException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;

@Component
@Order(10)
@Slf4j
public class SSOFilter extends GenericFilterBean {

    public static final String PCTS_REPLACE = "_pcts_";
    @Autowired SSOProcessor ssoProcessor;
    @Value("${app.irmp.common.auth.url.login}") String loginUrl;
    @Value("${app.irmp.common.auth.url.logout}") String logoutUrl;

    @Override
    public void doFilter(ServletRequest request1, ServletResponse response1, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) request1;
        HttpServletResponse response = (HttpServletResponse) response1;
        String requestURI = getRequestURI(request);
        log.debug("request path:{}", requestURI);
        if ("/login-url".equals(requestURI)) {
            response.setContentType("application/json");
            response.setStatus(HttpStatus.OK.value());
            String url = loginUrl;
            if (loginUrl.indexOf("{redirect_uri}") > 0) {
                //e.g. http
                StringBuffer serviceRoot = request.getRequestURL();
                serviceRoot.delete(serviceRoot.indexOf("/login-url"), serviceRoot.length());
                String path = request.getParameter("path");
                if (path == null) {
                    path = "/";
                }
                String encodePath = encodeURI(path);
                serviceRoot.append("/login-sso?path=").append(encodePath);

                log.debug("Service root: {}", serviceRoot);
                url = loginUrl.replace("{redirect_uri}", URLEncoder.encode(serviceRoot.toString(), StandardCharsets.UTF_8));
                log.debug("sso redirect to: {}", url);
            }
            response.getWriter().write(url);
            return;
        }
        if ("/logout".equals(requestURI)) {
            ssoProcessor.logout(request, response);
            if (StringUtils.isEmpty(loginUrl)) {
                response.setContentType("application/json");
                response.setStatus(HttpStatus.OK.value());
                response.getWriter().write("You have logout!");
            } else {
                response.sendRedirect(logoutUrl);
            }
            return;
        }

        try {

            if (HttpMethod.GET.name().equals(request.getMethod())) {
                String code = request.getParameter("code");
                if (code != null) {
                    ssoProcessor.processSSO(request, response);
                }
            }
            //登录处理完成后，重定向到指定的页面
            if ("/login-sso".equals(requestURI) || "/login-nolog".equals(requestURI)) {
                String encPath = request.getParameter("path");
                String path = decodeURI(encPath);
                log.debug("login-sso done, redirect to {}", path);
                response.sendRedirect(path);
                return;
            }
            chain.doFilter(request1, response1);
        } catch (AuthenticationException e) {
            log.error("Authentication failed: ", e);
            response.setContentType("application/json");
            response.sendError(HttpStatus.UNAUTHORIZED.value(), e.getMessage());
//            response.sendRedirect(loginUri);
        }

    }

    public static String decodeURI(String encPath) {
        encPath = encPath.replaceAll(PCTS_REPLACE, "%");
        String path = URLDecoder.decode(encPath, StandardCharsets.UTF_8);
        return path;
    }

    public static String encodeURI(String path) {
        String encodePath = URLEncoder.encode(path, StandardCharsets.UTF_8);
        encodePath = encodePath.replaceAll("%", PCTS_REPLACE);
        return encodePath;
    }

    private static String getRequestURI(HttpServletRequest request) {
        String requestURI = request.getRequestURI();
        String contextPath = request.getContextPath();
        if (contextPath.length() > 1){
            requestURI = StringUtils.removeStart(requestURI, contextPath);
        }
        return requestURI;
    }
}
